Skip to content

feat(source-generators): add class-based middleware support with UseMiddleware<T>()#257

Merged
j-d-ha merged 25 commits into
mainfrom
feature/#198-add-class-based-middleware
Dec 19, 2025
Merged

feat(source-generators): add class-based middleware support with UseMiddleware<T>()#257
j-d-ha merged 25 commits into
mainfrom
feature/#198-add-class-based-middleware

Conversation

@j-d-ha

@j-d-ha j-d-ha commented Dec 18, 2025

Copy link
Copy Markdown
Collaborator

🚀 Pull Request

📋 Summary

This PR implements comprehensive class-based middleware support through UseMiddleware<T>(), enabling reusable, testable middleware with automatic dependency injection. This complements the existing inline middleware delegates and provides a familiar pattern for developers coming from ASP.NET Core.

Key features:

  • Source-generated UseMiddleware<T>() method with zero reflection overhead
  • Automatic constructor parameter resolution from DI container
  • Support for [FromServices], [FromKeyedServices], and [FromArguments] attributes
  • Constructor selection via [MiddlewareConstructor] attribute
  • Automatic disposal of middleware instances implementing IDisposable/IAsyncDisposable
  • Compile-time validation with diagnostics LH0005 and LH0006
  • Comprehensive documentation with real-world examples

Implementation details:

  • Constructor parameters without attributes check args first, then fall back to DI
  • Multiple constructor support with automatic selection (most parameters) or explicit [MiddlewareConstructor]
  • Per-invocation middleware lifecycle (instances created/disposed per Lambda invocation)
  • All constructor parameters must be resolvable at compile-time or runtime

✅ Checklist

  • My changes build cleanly
  • I've added/updated relevant tests
  • I've added/updated documentation or README
  • I've followed the coding style for this project
  • I've tested the changes locally (if applicable)

🧪 Related Issues or PRs

Closes #198


💬 Notes for Reviewers

Documentation: The middleware guide (docs/guides/middleware.md) has been significantly expanded with:

  • Detailed comparison of inline vs. class-based middleware
  • Real-world examples (JWT auth, distributed tracing, caching, rate limiting)
  • Testing patterns
  • Common middleware patterns
  • Complete API reference for parameter attributes

Example project: Added MinimalLambda.Example.ClassMiddleware to demonstrate usage patterns.

Diagnostics:

  • LH0005: Multiple constructors marked with [MiddlewareConstructor]
  • LH0006: Middleware type must be a concrete class

Testing: Unit tests include snapshot verification of generated code and validation of all parameter resolution scenarios.

- Updated version in Directory.Build.props file.
- Introduced a new example project for Class Middleware.
- Configured project settings, references, and dependencies.
- Added appsettings.json for logging and LambdaHost configuration.
- Included launchSettings.json with environment variable presets.
- Set up a Lambda application builder and configured request/response handling.
- Implemented a simple event handler mapping example.
- Added `Request` and `Response` record definitions for the example.
- Implemented `ILambdaMiddleware` interface to define middleware behavior.
- Added `UseMiddleware<T>()` syntax interception using source generators.
- Introduced `UseMiddlewareTInfo` struct to store middleware-related metadata.
- Extended incremental generator for middleware syntax analysis and metadata collection.
- Created `MiddlewareConstructorAttribute` and `FromArgumentsAttribute` for middleware constructors.
- Included unit tests to verify `UseMiddleware<T>()` functionality.
- Added support for capturing multiple constructors and attributes in `ConstructorInfo`.
- Introduced `ClassInfo.Create()` and `ConstructorInfo.Create()` for metadata generation.
- Updated `UseMiddlewareTInfo` to eliminate redundant `ConstructorInfos` field.
- Extended `ParameterInfo` with attribute name tracking via `AttributeNames`.
- Adjusted `UseMiddlewareTSyntaxProvider` to use the updated `ClassInfo` structure.
- Enhanced unit tests to validate middleware with multiple constructors and attributes.
…` calls

- Implemented `UseMiddlewareTSource.Generate` for rendering middleware invocation calls.
- Updated `LambdaHostOutputGenerator` to include middleware calls in generated output.
- Renamed `UseMiddlewareTInfo` to `UseMiddlewareTInfos` in `CompilationInfo` for consistency.
…onstructor caching and templates

- Introduced `UseMiddlewareT.scriban` template for generating middleware invocation methods.
- Added constructor caching mechanism in `UseMiddlewareExtensions` for optimized resolution.
- Replaced `ConstructorInfo` with `MethodInfo` for improved compatibility and flexibility.
- Updated `ClassInfo` to include `ShortName` for contextual middleware references.
- Adjusted `UseMiddlewareTSource` to prioritize `[MiddlewareConstructor]` or default constructors.
- Refactored unit tests to reflect changes in middleware constructor handling.
…removing redundant comments

- Removed outdated and unnecessary comments from `UseMiddlewareT.scriban`.
- Streamlined code for improved readability and maintainability.
…lidation and improved codegen

- Added validation for `[MiddlewareConstructor]` to ensure parameters are provided explicitly in `args`.
- Optimized `UseMiddlewareT.scriban` to handle optional and required parameters with proper assignments.
- Updated `GeneratorConstants` to simplify attribute constants' format and naming.
- Improved `UseMiddlewareLambdaApplicationExtensions` to accept `params object[] args`.
- Refactored `UseMiddlewareTSource` to include support for parameter assignment logic.
…UseMiddleware<T>`

- Introduced `FromServicesAttribute` to enable service injection for middleware parameters.
- Updated `UseMiddlewareT.scriban` to resolve parameters marked with `FromServicesAttribute`.
- Enhanced `UseMiddlewareTSource` to detect `FromServicesAttribute` and assign parameters correctly.
- Added `FromServices` constant to `GeneratorConstants` for attribute recognition.
…able parameter types

- Replaced `parameter.fully_qualified_type` with `parameter.fully_qualified_type_not_null` in template.
- Added `RemoveTrailingChar` helper method to strip nullable indicator from parameter types.
- Updated `UseMiddlewareTSource` to include non-nullable type processing for `FromServices`.
…r `FromServices` parameters

- Modified `UseMiddlewareT.scriban` to skip cache initialization for `FromServices` parameters.
- Adjusted `BuildResolutionCache` logic to exclude `FromServices` parameters from cache assignments.
… attribute validation

- Introduced diagnostic rule `LH0005` to ensure `[MiddlewareConstructor]` is used by only one constructor.
- Updated `DiagnosticGenerator` to detect and report multiple constructors using the attribute.
- Added `Diagnostics.MultipleConstructorsWithAttribute` descriptor for the new rule.
…ribute validation

- Added `Test_MiddlewareClassHasMoreThanOneMiddlewareConstructorAttribute` to validate diagnostic `LH0005`.
- Ensures an error is raised if multiple `[MiddlewareConstructor]` attributes are applied.
…omServices` optimization

- Added `AllFromServices` property in `UseMiddlewareTSource` to track parameters fully marked as `FromServices`.
- Updated `UseMiddlewareT.scriban` to skip resolution cache initialization if `AllFromServices` is true.
- Introduced `_cacheBuilt` flag to simplify cache-building logic for mixed parameter sources.
- Optimized `BuildResolutionCache` to handle scenarios where services are exclusively used.
…eMiddleware<T>`

- Enhanced `UseMiddlewareT.scriban` to handle `IDisposable` and `IAsyncDisposable` middleware.
- Added interface checks in `UseMiddlewareTSource` to identify disposable middleware types.
- Extended `ClassInfo` with `ImplementedInterfaces` and helper method `IsInterfaceImplemented`.
- Updated unit tests to verify scenarios with disposable middleware.
- Refactored code generation to properly manage lifecycle of disposable middleware instances.
- Added detailed XML documentation for `FromArgumentsAttribute`, `FromServicesAttribute`, and
  `MiddlewareConstructorAttribute` to explain usage and behavior.
- Included examples demonstrating use cases for each attribute.
- Enhanced `UseMiddlewareLambdaApplicationExtensions` with inline comments for better clarity and
  usability.
…ests

- Removed redundant `lambda.MapHandler` and `lambda.RunAsync` calls from existing test cases.
- Added comprehensive snapshot tests to verify generated code for various middleware scenarios:
  - Middleware with abstract classes.
  - Middleware with constructor arguments from services and keyed services.
  - Middleware with mixed parameter sources.
  - Middleware implementing `IDisposable` and `IAsyncDisposable`.
- Ensured better coverage and clarity for middleware usage scenarios.
…tion

- Introduced diagnostic rule `LH0006` to ensure middleware types are concrete classes.
- Updated `DiagnosticGenerator` to detect and report non-concrete middleware types like interfaces
  and abstract classes.
- Added `Diagnostics.MustBeConcreteType` descriptor for the new rule.
- Included a unit test `Test_MiddlewareClassMustNotBeAbstractOrAnInterface` to verify `LH0006`.
- Updated `AnalyzerReleases.Unshipped.md` to document the new rule.
…support

- Added support for resolving the location of generic type arguments in `UseMiddleware<T>`.
- Enhanced `TypeSymbolExtensions` with a `GetTypeKind` method to determine precise type definitions.
- Updated `ClassInfo` to include `TypeKind` for better type classification and diagnostics.
- Improved middleware code generation to incorporate generic argument location and accurate type info.
- Refactored `GeneratorConstants` to adjust attribute namespaces for consistency.
- Enhanced documentation for `ILambdaMiddleware` to provide detailed usage information.
- Added additional validation block in `DiagnosticGenerator` for middleware class type checks.
- Refactored XML documentation to consolidate paragraphs and improve readability.
- Streamlined multiple attribute and interface summaries by reducing excessive line breaks.
…aches

- Added detailed documentation on inline and class-based middleware styles.
- Included examples for both approaches with best practice recommendations.
- Explained parameter resolution using constructor attributes like `[FromServices]`.
- Added common patterns and lifecycle management details for middleware.
- Enhanced ordering strategy section with mixed inline and class-based examples.
- Simplified explanations for ASP.NET Core middleware similarities and invocation scopes.
- Improved readability by restructuring examples and condensing redundant content.
- Clarified usage of `Features` and added new example for request start time in `Items`.
- Reworked notes on class-based middleware for better alignment with reusable package guidance.
- Updated formatting for tips, warnings, and compile-time diagnostics to enhance presentation.
@github-actions github-actions Bot added the type: feat New feature label Dec 18, 2025
@codecov

codecov Bot commented Dec 18, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.77888% with 34 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ourceGenerators/Extensions/TypeSymbolExtensions.cs 20.00% 16 Missing and 4 partials ⚠️
...inimalLambda.SourceGenerators/Models/MethodInfo.cs 77.77% 0 Missing and 4 partials ⚠️
...rs/SyntaxProviders/UseMiddlewareTSyntaxProvider.cs 91.66% 1 Missing and 3 partials ⚠️
...enerators/OutputGenerators/UseMiddlewareTSource.cs 96.90% 1 Missing and 2 partials ⚠️
...ourceGenerators/Diagnostics/DiagnosticGenerator.cs 92.85% 0 Missing and 2 partials ⚠️
...imalLambda.SourceGenerators/Models/LocationInfo.cs 90.00% 0 Missing and 1 partial ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #257      +/-   ##
==========================================
- Coverage   88.33%   88.32%   -0.01%     
==========================================
  Files         130      135       +5     
  Lines        3129     3410     +281     
  Branches      340      374      +34     
==========================================
+ Hits         2764     3012     +248     
- Misses        232      250      +18     
- Partials      133      148      +15     
Files with missing lines Coverage Δ
...Lambda.SourceGenerators/Diagnostics/Diagnostics.cs 100.00% <100.00%> (ø)
...SourceGenerators/MapHandlerIncrementalGenerator.cs 92.72% <100.00%> (+0.80%) ⬆️
...MinimalLambda.SourceGenerators/Models/ClassInfo.cs 100.00% <100.00%> (ø)
...lLambda.SourceGenerators/Models/CompilationInfo.cs 100.00% <100.00%> (ø)
...bda.SourceGenerators/Models/KeyedServiceKeyInfo.cs 80.39% <100.00%> (ø)
...malLambda.SourceGenerators/Models/ParameterInfo.cs 98.14% <100.00%> (+0.27%) ⬆️
...mbda.SourceGenerators/Models/UseMiddlewareTInfo.cs 100.00% <100.00%> (ø)
...tors/OutputGenerators/LambdaHostOutputGenerator.cs 100.00% <100.00%> (ø)
...SyntaxProviders/Extractors/HandlerInfoExtractor.cs 80.55% <100.00%> (ø)
...ers/LambdaApplicationBuilderBuildSyntaxProvider.cs 93.10% <100.00%> (ø)
... and 6 more

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ad77c7f...a6ab252. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…d maintainability

- Replaced static factory methods in `LocationInfo` with extension methods for cleaner syntax.
- Simplified `LocationInfo` creation across multiple syntax providers using new extension methods:
  - Updated creation calls in `ParameterInfo`, `UseMiddlewareTSyntaxProvider`, and others.
- Consolidated duplication of logic for `SyntaxNode`, `ISymbol`, and `Location` into reusable extensions.
- Enhanced readability and reduced redundant code across the source generator logic.
…Example.ClassMiddleware`

- Introduced a `Middleware` class implementing `ILambdaMiddleware` to demonstrate class-based usage.
- Enhanced logging in middleware to log both request and response details.
- Updated `Program.cs` to include middleware and log key invocation events.
- Improved example readability and showcased middleware's role in request/response processing.
@sonarqubecloud

sonarqubecloud Bot commented Dec 19, 2025

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
2 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@j-d-ha
j-d-ha merged commit 7030cfd into main Dec 19, 2025
10 checks passed
@j-d-ha
j-d-ha deleted the feature/#198-add-class-based-middleware branch December 19, 2025 01:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(host): add class-based middleware registration via ILambdaMiddleware interface

1 participant